package com.xiaomaoguai.fcp.pre.kepler.convert.configuration;

import com.xiaomaoguai.fcp.pre.kepler.convert.anno.ConvertClient;
import com.xiaomaoguai.fcp.pre.kepler.convert.core.support.ConvertClientFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;

/**
 * @fileName: ConvertClientsRegistrar.java
 * @author: WeiHui
 * @date: 2018/11/20 21:38
 * @version: v1.0.0
 * @since JDK 1.8
 */
public class ConvertClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

	private static final Logger log = LoggerFactory.getLogger(ConvertClientsRegistrar.class);

	private ResourceLoader resourceLoader;

	private ClassLoader classLoader;

	private Environment environment;

	public ConvertClientsRegistrar() {
	}

	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}

	@Override
	public void setEnvironment(Environment environment) {
		this.environment = environment;
	}

	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
		ClassPathScanningCandidateComponentProvider scanner = getScanner();
		scanner.setResourceLoader(this.resourceLoader);
		scanner.addIncludeFilter(new AnnotationTypeFilter(ConvertClient.class));
		//获取要扫描的包路径
		String packageName = ClassUtils.getPackageName(metadata.getClassName());
		log.debug("====>ConvertClient scan package:{}", packageName);
		Set<String> className = new HashSet<>();
		Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(packageName);
		for (BeanDefinition candidateComponent : candidateComponents) {
			if (candidateComponent instanceof AnnotatedBeanDefinition) {
				// verify annotated class is an interface
				AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
				AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
				Assert.isTrue(annotationMetadata.isInterface(), "@ConvertClient can only be specified on an interface");
				className.add(candidateComponent.getBeanClassName());
			}
		}
		for (String clazz : className) {
			try {
				log.debug("====>register convert-client:{}", clazz);
				GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
				genericBeanDefinition.setBeanClass(ConvertClientFactoryBean.class);
				String[] stringArray = StringUtils.delimitedListToStringArray(clazz, ".");
				String beanName = StringUtils.uncapitalize(stringArray[stringArray.length - 1]);
				genericBeanDefinition.getPropertyValues().add("serviceInterface", ClassUtils.forName(clazz, classLoader));
				genericBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
				registry.registerBeanDefinition(beanName, genericBeanDefinition);
			} catch (ClassNotFoundException e) {
				log.error("====>注册Bean:[{}]异常", clazz, e);
			}
		}
	}

	/**
	 * 扫描注解了ConvertClient的类
	 */
	private ClassPathScanningCandidateComponentProvider getScanner() {
		return new ClassPathScanningCandidateComponentProvider(false, this.environment) {

			@Override
			protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
				if (beanDefinition.getMetadata().isIndependent()) {
					if (beanDefinition.getMetadata().isInterface()
							&& beanDefinition.getMetadata().getInterfaceNames().length == 1
							&& Annotation.class.getName().equals(beanDefinition.getMetadata().getInterfaceNames()[0])) {
						try {
							Class<?> target = ClassUtils.forName(beanDefinition.getMetadata().getClassName(), ConvertClientsRegistrar.this.classLoader);
							return !target.isAnnotation();
						} catch (Exception ex) {
							log.error("Could not load target class: " + beanDefinition.getMetadata().getClassName(), ex);
						}
					}
					return true;
				}
				return false;
			}
		};
	}

}
